package com.smartstate.ems.mqtt.callback;


import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.smartstate.ems.dto.EquipmentDTO;
import com.smartstate.ems.entity.Equipment;
import com.smartstate.ems.entity.EquipmentConfiguration;
import com.smartstate.ems.mapper.EquipmentConfigMapper;
import com.smartstate.ems.mqtt.client.MyMQTTClient;
import com.smartstate.ems.service.EquipmentConfigService;
import com.smartstate.ems.service.EquipmentService;
import com.smartstate.ems.util.SpringUtils;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

@Slf4j
public class MyMQTTCallback implements MqttCallback {

    private static final Logger LOGGER = LoggerFactory.getLogger(MyMQTTCallback.class);

    private MyMQTTClient myMQTTClient;


    private static final ThreadPoolExecutor threadpool = new ThreadPoolExecutor(100, 200,
            10L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());

    public MyMQTTCallback(MyMQTTClient myMQTTClient) {
        this.myMQTTClient = myMQTTClient;
    }

    /**
     * 丢失连接，可在这里做重连
     * 只会调用一次
     *
     * @param throwable
     */
    @Override
    public void connectionLost(Throwable throwable) {
    }

    /**
     * @param topic
     * @param message
     * @throws Exception subscribe后得到的消息会执行到这里面
     */
    @Override
    public void messageArrived(String topic, MqttMessage message) throws Exception {
        EquipmentService equipmentService = SpringUtils.getBean(EquipmentService.class);
        EquipmentConfigService equipmentConfigService = SpringUtils.getBean(EquipmentConfigService.class);
        EquipmentConfigMapper equipmentConfigMapper = SpringUtils.getBean(EquipmentConfigMapper.class);
        String msg = new String(message.getPayload(), "UTF-8");
//        ArrayList<EquipmentDTO.AddressData> objects = new ArrayList<>();
        HashMap<String, List<EquipmentDTO.AddressData>> hashMap = new HashMap<>();
        //IOT第一次推数据上来
        if (topic.endsWith("FIRST")) {
            List<EquipmentDTO.AddressData> addressDataList = JSONArray.parseArray(msg, EquipmentDTO.AddressData.class);
            if (!CollectionUtils.isEmpty(addressDataList)) {
                for (EquipmentDTO.AddressData addressData : addressDataList) {
                    String dataId = addressData.getDataId();
                    String deviceId = dataId.substring(0, dataId.substring(0, dataId.indexOf(".")).length());
                    System.out.println("deviceId = " + deviceId);
                    Equipment one = equipmentService.getOne(new QueryWrapper<Equipment>().eq("deviceId", deviceId));
                    if (one != null) {
                        if (hashMap.get(deviceId) == null) {
                            //保存了这个设备，就根据设备id查找设备属性表，看有没有数据已保存
                            EquipmentConfiguration configuration = equipmentConfigService.getOne(new QueryWrapper<EquipmentConfiguration>().eq("deviceId", deviceId));
                            if (configuration != null && configuration.getTags() != null) {
                                //已经有保存的数据
                                List<EquipmentDTO.AddressData> dataList = JSONArray.parseArray(configuration.getTags(), EquipmentDTO.AddressData.class);
                                EquipmentDTO.AddressData addressData2 = dataList.stream().filter(addressData1 -> (addressData1.getDataId().equals(addressData.getDataId()))).findAny().orElse(null);
                                if (addressData2 == null) {
                                    //没有相同的属性DataId
                                    EquipmentDTO.AddressData data = new EquipmentDTO.AddressData();
                                    BeanUtils.copyProperties(addressData, data);
                                    data.setUp(addressData.getUpLimit());
                                    data.setDown(addressData.getDownLimit());
                                    data.setDeviation(addressData.getDeviation());
                                    data.setAttributeName(addressData.getDataId().substring(addressData.getDataId().substring(0, data.getDataId().indexOf(".")).length() + 1, addressData.getDataId().length()));
                                    dataList.add(data);
                                } else {
                                    //有相同的属性DataId
                                    for (EquipmentDTO.AddressData data : dataList) {
                                        if (data.getDataId().equals(addressData.getDataId())) {
                                            data.setIsAlarm(addressData.getIsAlarm());
                                            data.setDeviation(addressData.getDeviation());
                                            data.setUp(addressData.getUpLimit());
                                            data.setDown(addressData.getDownLimit());
                                            data.setDeviation(addressData.getDeviation());
                                        }
                                    }
                                }
                                hashMap.put(deviceId, dataList);
                            } else {
                                // 没有保存的数据
                                ArrayList<EquipmentDTO.AddressData> objects = new ArrayList<>();
                                addressData.setUp(addressData.getUpLimit());
                                addressData.setDown(addressData.getDownLimit());
                                addressData.setAttributeName(addressData.getDataId().substring(addressData.getDataId().substring(0, addressData.getDataId().indexOf(".")).length() + 1, addressData.getDataId().length()));
                                objects.add(addressData);
                                hashMap.put(deviceId, objects);
                            }
                        } else {
                            List<EquipmentDTO.AddressData> dataList = hashMap.get(deviceId);
                            EquipmentDTO.AddressData orElse = dataList.stream().filter(addressData1 -> addressData1.getDataId().equals(addressData.getDataId())).findAny().orElse(null);
                            if (orElse == null) {
                                //没有相同的属性DataId
                                EquipmentDTO.AddressData data = new EquipmentDTO.AddressData();
                                BeanUtils.copyProperties(addressData, data);
                                data.setUp(addressData.getUpLimit());
                                data.setDown(addressData.getDownLimit());
                                data.setAttributeName(addressData.getDataId().substring(addressData.getDataId().substring(0, addressData.getDataId().indexOf(".")).length() + 1, addressData.getDataId().length()));
                                dataList.add(data);
                            } else {
                                for (EquipmentDTO.AddressData data : dataList) {
                                    if (data.getDataId().equals(addressData.getDataId())) {
                                        data.setIsAlarm(addressData.getIsAlarm());
                                        data.setDeviation(addressData.getDeviation());
                                        data.setUp(addressData.getUpLimit());
                                        data.setDown(addressData.getDownLimit());
                                    }
                                }
                            }
                            hashMap.put(deviceId, dataList);
                        }
                    }
                }
                System.out.println("hashMap = " + hashMap);
                //保存进数据库
                Set<String> keySet = hashMap.keySet();
                for (String deviceId : keySet) {
                    List<EquipmentDTO.AddressData> data = hashMap.get(deviceId);
                    Equipment one = equipmentService.getOne(new QueryWrapper<Equipment>().eq("deviceId", deviceId));
                    String tags = JSON.toJSONString(data);
                    EquipmentConfiguration configuration = equipmentConfigService.getOne(new QueryWrapper<EquipmentConfiguration>().eq("deviceId", deviceId));
                    if (configuration == null) {
                        EquipmentConfiguration equipmentConfiguration = new EquipmentConfiguration();
                        equipmentConfiguration.setType(one.getType());
                        equipmentConfiguration.setId(IdUtil.simpleUUID());
                        equipmentConfiguration.setDeviceId(deviceId);
                        equipmentConfiguration.setTags(tags);
                        boolean insert = equipmentConfigService.save(equipmentConfiguration);
                        System.out.println("insert = " + insert);
                    } else {
                        configuration.setTags(tags);
                        boolean update = equipmentConfigService.updateById(configuration);
                        System.out.println("update = " + update);
                    }
                }
                //把hashMap里面的数据清空
                hashMap.clear();
            }
        }
        //不是IOT第一次推送
        else {
            List<EquipmentDTO.AddressData> addressDataList = JSONArray.parseArray(msg, EquipmentDTO.AddressData.class);
            if (!CollectionUtils.isEmpty(addressDataList)) {
                for (EquipmentDTO.AddressData addressData : addressDataList) {
                    String dataId = addressData.getDataId();
                    String deviceId = dataId.substring(0, dataId.substring(0, dataId.indexOf(".")).length());
                    Equipment one = equipmentService.getOne(new QueryWrapper<Equipment>().eq("deviceId", deviceId));
                    if (one != null) {
                        if (hashMap.get(deviceId) != null) {
                            List<EquipmentDTO.AddressData> dataList = hashMap.get(deviceId);
                            EquipmentDTO.AddressData orElse = dataList.stream().filter(addressData1 -> addressData1.getDataId().equals(addressData.getDataId())).findAny().orElse(null);
                            if (orElse == null) {
                                //没有相同的设备属性
                                addressData.setUp(addressData.getUpLimit());
                                addressData.setDown(addressData.getDownLimit());
                                addressData.setAttributeName(addressData.getDataId().substring(addressData.getDataId().substring(0, addressData.getDataId().indexOf(".")).length() + 1, addressData.getDataId().length()));
                                dataList.add(addressData);
                            } else {
                                //有相同的设备属性
                                for (EquipmentDTO.AddressData data : dataList) {
                                    if (data.getDataId().equals(addressData.getDataId())) {
                                        data.setDown(addressData.getDownLimit());
                                        data.setUp(addressData.getUpLimit());
                                        data.setIsAlarm(addressData.getIsAlarm());
                                        data.setDeviation(addressData.getDeviation());
                                    }
                                }
                                hashMap.put(deviceId, dataList);
                            }
                        } else {
                            EquipmentConfiguration configuration = equipmentConfigService.getOne(new QueryWrapper<EquipmentConfiguration>().eq("deviceId", deviceId));
                            if (configuration != null && configuration.getTags() != null) {
                                List<EquipmentDTO.AddressData> dataList = JSONArray.parseArray(configuration.getTags(), EquipmentDTO.AddressData.class);
                                EquipmentDTO.AddressData orElse = dataList.stream().filter(addressData1 -> addressData1.getDataId().equals(addressData.getDataId())).findAny().orElse(null);
                                if (orElse == null) {
                                    addressData.setUp(addressData.getUpLimit());
                                    addressData.setDown(addressData.getDownLimit());
                                    addressData.setAttributeName(addressData.getDataId().substring(addressData.getDataId().substring(0, addressData.getDataId().indexOf(".")).length() + 1, addressData.getDataId().length()));
                                    dataList.add(addressData);
                                } else {
                                    for (EquipmentDTO.AddressData data : dataList) {
                                        if (data.getDataId().equals(addressData.getDataId())) {
                                            data.setDown(addressData.getDownLimit());
                                            data.setUp(addressData.getUpLimit());
                                            data.setIsAlarm(addressData.getIsAlarm());
                                            data.setDeviation(addressData.getDeviation());
                                        }
                                    }
                                }
                                hashMap.put(deviceId, dataList);
                            } else {
                                ArrayList<EquipmentDTO.AddressData> objects = new ArrayList<>();
                                addressData.setUp(addressData.getUpLimit());
                                addressData.setDown(addressData.getDownLimit());
                                addressData.setAttributeName(addressData.getDataId().substring(addressData.getDataId().substring(0, addressData.getDataId().indexOf(".")).length() + 1, addressData.getDataId().length()));
                                objects.add(addressData);
                                hashMap.put(deviceId, objects);
                            }
                        }
                    }
                }
                //保存进数据库
                Set<String> keySet = hashMap.keySet();
                for (String deviceId : keySet) {
                    List<EquipmentDTO.AddressData> data = hashMap.get(deviceId);
                    Equipment one = equipmentService.getOne(new QueryWrapper<Equipment>().eq("deviceId", deviceId));
                    String tags = JSON.toJSONString(data);
                    EquipmentConfiguration configuration = equipmentConfigService.getOne(new QueryWrapper<EquipmentConfiguration>().eq("deviceId", deviceId));
                    if (configuration == null) {
                        EquipmentConfiguration equipmentConfiguration = new EquipmentConfiguration();
                        equipmentConfiguration.setType(one.getType());
                        equipmentConfiguration.setId(IdUtil.simpleUUID());
                        equipmentConfiguration.setDeviceId(deviceId);
                        equipmentConfiguration.setTags(tags);
                        boolean insert = equipmentConfigService.save(equipmentConfiguration);
                        System.out.println("insert = " + insert);
                    } else {
                        configuration.setTags(tags);
                        boolean update = equipmentConfigService.updateById(configuration);
                        System.out.println("update = " + update);
                    }
                }
                hashMap.clear();
            }
        }

//        log.info("接收消息主题 : {}，接收消息内容 : {}", topic, msg);
    }

    /**
     * Json格式转译
     *
     * @param jsonObj
     * @return
     */
    public Map<String, Object> analysis(JSONObject jsonObj) {
        JSONArray readResults = jsonObj.getJSONArray("values");
        Map<String, Object> map = new HashMap<>();
        for (int i = 0; i < readResults.size(); i++) {
            JSONObject jsonObject = readResults.getJSONObject(i);
            String[] split = jsonObject.getString("id").split("\\.");
            String id = split[split.length - 1];
            Object value = 0;
            if (Boolean.parseBoolean(jsonObject.get("q").toString())) {
                value = jsonObject.get("v");
            }
            map.put(id, value);
        }
        return map;
    }

    /**
     * 消息到达后
     * subscribe后，执行的回调函数
     *
     * @param s
     * @param mqttMessage
     * @throws Exception
     */

    /**
     * publish后，配送完成后回调的方法
     *
     * @param iMqttDeliveryToken
     */
    @Override
    public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
        LOGGER.info("==========deliveryComplete={}==========", iMqttDeliveryToken.isComplete());
    }
}
